﻿//////////////////////////////////////////////////////////////////////////////////
//
// Project            : SimpleProxySwitch
// Module             : SimpleProxySwitch
// Description        : Main program.
// 
// Repository         : $URL$
// Last changed by    : $LastChangedBy$
// Revision           : $LastChangedRevision$
// Last Changed       : $LastChangedDate$
// Author             : $Author$
//
// Id                 : $Id$
//
// Copyright          : (c) 2010 Torsten Bär
//
// Published under the MIT License. See license.rtf or http://www.opensource.org/licenses/mit-license.php.
//
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using log4net;
using ProxySwitch.Properties;

namespace ProxySwitch
{
   /// <summary>
   /// Main program if simple proxy switch.
   /// </summary>
   static class Program
   {
      private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

      /// <summary>
      /// The main entry point for the application.
      /// </summary>
      [STAThread]
      static void Main(string[] args)
      {
         // configure logging
         log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "log4net.config")));

         // connect to unhandled exception handlers
         AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
         Application.ThreadException += Application_ThreadException;
         Application.ApplicationExit += Application_ApplicationExit;

         // upgrade properties if needed
         // prevents deletion on every new install
         if (Settings.Default.UpgradeNeeded)
         {
            Log.Debug("Upgrading settings file");

            Settings.Default.Upgrade();
            Settings.Default.UpgradeNeeded = false;
            Settings.Default.Save();

            Log.Debug("Settings file upgraded");
         }

         Log.Debug("Preparing application");

         // enable visual styles
         Application.EnableVisualStyles();
         Application.SetCompatibleTextRenderingDefault(false);

         Log.Debug("Check for running instance");

         //
         // detect running app with mutex
         //

         string guid = ((GuidAttribute)Attribute.GetCustomAttribute(typeof(Program).Assembly, typeof(GuidAttribute))).Value;

         bool createdNew;
         using (new Mutex(false, guid, out createdNew))
         {
            Log.DebugFormat("Current is {0} first the instance", createdNew ? "the" : "not the");

            // new mutex -> only instance
            if (createdNew)
            {
               Log.Debug("Checking arguments");

               // no args provided -> run window mode
               if (args.Length == 0)
               {
                  Log.Debug("Running window mode");

                  ScheduleHelper.DisableSchedule();
                  Application.Run(new MainForm());
                  ScheduleHelper.EnableSchedule();
               }
               // check args
               else if(String.Compare(args[0], "/applyProxy", true) == 0)
               {
                  Log.Debug("Running apply proxy mode");

                  Log.Debug("Applying proxy for current network");
                  try
                  {
                     List<ProxySetting> proxySettings = XmlSerializer<List<ProxySetting>>.Deserialize(Settings.Default.ProxySettings);

                     Log.DebugFormat("Deserialized {0} settings", proxySettings.Count);

                     if (Network.SetProxyForCurrentNetwork(proxySettings))
                     {
                        Log.Debug("Proxy applied");

                        ShowNotifyIconAndWait();
                     }
                  }
                  catch (Exception exception)
                  {
                     Log.Error("Error on apply settings", exception);
                  }
               }
               else
               {
                  Log.Debug("Error: Printing usage");
                  Console.WriteLine("Usage: ProxySwitch.exe /applyProxy");
                  Environment.ExitCode = 2;
               }
            }
            else
            {
               Log.Debug("Getting running process");

               // get running process
               Process process = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).FirstOrDefault();

               // process is running windowed app
               if (process.StartInfo.Arguments.Length == 0)
               {
                  Log.Debug("Process is running window app");

                  try
                  {
                     Log.Debug("Try to focus main window");

                     // bring to front
                     Control.FromHandle(process.MainWindowHandle).Show();
                     Environment.ExitCode = 0;
                  }
                  catch (Exception e)
                  {
                     Log.Error("Error", e);

                     MessageBox.Show("Error: Application is running but main window couln't be opened.\n\n" + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                     Environment.ExitCode = 1;
                  }
               }
               
               // running task -> ignore call
               if(args.Length > 0)
               {
                  Log.Debug("App is still running");
                  // running from command line e.g. scheduler mode - ignore
                  Console.WriteLine("Still running");
               }
            }
         }

         Log.DebugFormat("Closing Application; ExitCode={0}", Environment.ExitCode);
      }

      /// <summary>
      /// Shows the notify icon and wait.
      /// </summary>
      private static void ShowNotifyIconAndWait()
      {
         Log.Debug("Creating NotifyIcon");

         const string titleText = "Simple Proxy Switch";
         using (NotifyIcon notifyIcon = new NotifyIcon
                                        {
                                           Visible = true,
                                           Icon = Resources.Globe, 
                                           BalloonTipIcon = ToolTipIcon.Info, 
                                           BalloonTipText = "Proxy " + (Network.ProxyEnabled ? "disabled" : Network.SystemProxy.Address), 
                                           BalloonTipTitle = titleText, 
                                           Text = titleText,
                                        })
         {
            Log.Debug("NotifyIcon initialized");

            using (ManualResetEvent resetEvnt = new ManualResetEvent(false))
            {
               notifyIcon.BalloonTipClosed += (sender, evtArgs) => resetEvnt.Set();

               if (Log.IsDebugEnabled)
                  notifyIcon.BalloonTipShown += (sender, evtArgs) => Log.Debug("BalloonTip shown");

               Log.Debug("Showing NotifyIcon");

               notifyIcon.ShowBalloonTip((int)TimeSpan.FromSeconds(10).TotalSeconds);
               resetEvnt.WaitOne();

               Log.Debug("NotifyIcon closed");
            }
         }
      }

      /// <summary>
      /// Handles the ThreadException event of the Application control.
      /// </summary>
      /// <param name="sender">The source of the event.</param>
      /// <param name="e">The <see cref="System.Threading.ThreadExceptionEventArgs"/> instance containing the event data.</param>
      static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
      {
         Log.Error("Error", e.Exception);
      }

      /// <summary>
      /// Handles the UnhandledException event of the CurrentDomain control.
      /// </summary>
      /// <param name="sender">The source of the event.</param>
      /// <param name="e">The <see cref="System.UnhandledExceptionEventArgs"/> instance containing the event data.</param>
      static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
      {
         Log.Error(String.Format("Error an is terminating: {0}", e.IsTerminating), e.ExceptionObject as Exception);
      }

      /// <summary>
      /// Handles the ApplicationExit event of the Application control.
      /// </summary>
      /// <param name="sender">The source of the event.</param>
      /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
      private static void Application_ApplicationExit(object sender, EventArgs e)
      {
         Log.Debug("Application exit");
      }
   }
}
